#ifndef __MY_FMT__
#define  __MY_FMT__
#include <ctime>
#include"level.hpp"
#include"message.hpp"
#include<vector>
#include<sstream>
#include<cassert>

namespace zylog{
    //抽象格式化子项--基类
    class FormatItem{
        public:
            using ptr=std::shared_ptr<FormatItem>;
            virtual void format(std::ostream &out,const LogMsg &msg)=0;
    };

    class MsgFormatItem:public FormatItem{
        public:
             virtual void format(std::ostream &out,const LogMsg &msg) override{
                out<<msg._payload;
             }
    };
    class LevelFormatItem:public FormatItem{
        public: 
            virtual void format(std::ostream &out,const LogMsg &msg) override{
                out<<LogLevel::toString(msg._level);
            }
    };
    class TimeFormatItem:public FormatItem{
        public:
            TimeFormatItem(const std::string &fmt="%H:%M:%S"):_time_fmt(fmt){}
            void format(std::ostream &out,const LogMsg &msg) override{
                struct tm t;
                localtime_r(&msg._ctime,&t);
                char tmp[32]={0};
                strftime(tmp,31,_time_fmt.c_str(),&t);
                out<<tmp;  }
        private:
            std::string _time_fmt;
    };
    class FileFormatItem:public FormatItem {
        public:
            void format(std::ostream &out,const LogMsg &msg) override{
                out<<msg._file;
            }
    };
    class LineFormatItem:public FormatItem{
        public:
            void format(std::ostream &out,const LogMsg &msg) override{
                out<<msg._line;
            }
    };
    class ThreadFormatItem:public FormatItem{
        public:
            void format(std::ostream &out,const LogMsg &msg) override{
                out<<msg._tid;
            }
    };
    class LoggerFormatItem:public FormatItem{
        public:
            void format(std::ostream &out,const LogMsg &msg) override{
                out<<msg._logger;
            }
    };
    class NlineFormatItem:public FormatItem{
        public:
            void format(std::ostream &out,const LogMsg &msg) override{
                out<<"\n";
                }
    };
    class TabFormatItem:public FormatItem{
        public:
            void format(std::ostream &out,const LogMsg &msg) override{
                out<<"\t";
            }
    };
    class OtherFormatItem:public FormatItem{
        public:
            OtherFormatItem(const std::string &str):_str(str){}
            void format(std::ostream&out,const LogMsg &msg)override{
                out<<_str;
            }
        private:
            std::string _str;
    };

/*
%d 表示日期,包含子格式{%H:%M:%S}
%t 表示线程ID
%c 表示日志器名称
%f 表示源码文件名
%l 表示源码行号
%p 表示日志级别
%T 表示制表符缩进
%m 表示主体消息
%n 表示换行
*/
   class Formatter{
public:
    using ptr=std::shared_ptr<Formatter>;
    Formatter(const std::string& pattern="[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"):
        _pattern(pattern){
            assert(parsePattern());//解析的时候初始化了_items
        }
    void format(std::ostream &out,const LogMsg&msg){
        for(auto &item:_items){
            item->format(out,msg);//将_items的内容逐个放入out,这个format是多态
        }
    }
    std::string format(const LogMsg &msg){
        std::stringstream ss;
        format(ss,msg);
        return ss.str();
    }
    private:
    bool parsePattern(){
        //1.对格式化规则字符串进行解析
        std::vector<std::pair<std::string,std::string>> fmt_order;
        size_t pos=0;
        std::string key,val;
        while(pos<_pattern.size()){
            //1.处理原始字符串--判断是否是%，不是就是原始字符
            if(_pattern[pos]!='%'){
                val.push_back(_pattern[pos++]);continue;
            }
            //能走下来就代表pos位置就是%字符，%%处理
            if(pos+1<_pattern.size()&&_pattern[pos+1]=='%'){
                val.push_back('%');pos+=2;continue;
            }
            //val不是空就代表有原始字符，放到fmt_order里
            if(val.empty()==false){
                fmt_order.push_back(std::make_pair("",val));
                val.clear();
            }
            //pos指向的是%位置，处理格式化字符
            pos+=1;
            if(pos==_pattern.size()){
                std::cout<<"%后没有对应的格式化字符"<<std::endl;
                return false;
            }
            //走到这就是有对应的格式化字符
            key=_pattern[pos];
            pos+=1;//这时候pos指向格式化字符之后的位置
            if(pos<_pattern.size()&&_pattern[pos]=='{'){
                //子串且pos是{向后走到子串内容
                pos+=1;
                while(pos<_pattern.size()&&_pattern[pos]!='}'){
                    val.push_back(_pattern[pos++]);
                }
                if(pos==_pattern.size())//说明走到最后也没有}
                {
                    std::cout<<"缺少}\n";
                    return false;
                }
                pos+=1;//因为走到这是指向}
            }
            fmt_order.push_back(std::make_pair(key,val));
            key.clear();
            val.clear();
        }
        for(auto&it:fmt_order){
            _items.push_back(createItem(it.first,it.second));
        }
        return true;
    }

FormatItem::ptr createItem(const std::string &key,const std::string&val){
    if(key=="d")return std::make_shared<TimeFormatItem>(val);
    if(key=="t")return std::make_shared<ThreadFormatItem>();
    if(key=="c")return std::make_shared<LoggerFormatItem>();
    if(key=="f")return std::make_shared<FileFormatItem>();
    if(key=="l")return std::make_shared<LineFormatItem>();
    if(key=="p")return std::make_shared<LevelFormatItem>();
    if(key=="T")return std::make_shared<TabFormatItem>();
    if(key=="m")return std::make_shared<MsgFormatItem>();
    if(key=="n")return std::make_shared<NlineFormatItem>();
    if(key.empty())return std::make_shared<OtherFormatItem>(val);
    std::cout<<"没有对应的格式化字符：%"<<key<<std::endl;
    abort();//立即终止当前进程，产生异常程序终止
    return FormatItem::ptr();//返回空的ptr
}
private:
std::string _pattern;
std::vector<FormatItem::ptr>_items;
};
}
#endif